#include <BLEDevice.h>
#include <BLEServer.h>
#include <BLEUtils.h>
#include <BLE2902.h>
#include <BluetoothContext.h>
#include <memory> // 必须引入

#include <esp_mac.h>

//服务监听
class MyServerCallbacks: public BLEServerCallbacks {
  private:
    BluetoothContext* context;
  public:
    MyServerCallbacks(BluetoothContext* ctx) : context(ctx) {}
    //当连接成功
    void onConnect(BLEServer* pServer) {
      context->setDeviceConnected(true);
      context->setInterval(300);
    };
    //当连接断开
    void onDisconnect(BLEServer* pServer) {
      context->setDeviceConnected(false);
      context->setInterval(2000);
      // 断开连接后，重新启动广播
      pServer->getAdvertising()->start();
    }
};

//信息监听
class MyCallbacks: public BLECharacteristicCallbacks {
  private:
    BluetoothContext* context;
  public:
    MyCallbacks(BluetoothContext* ctx) : context(ctx) {}
    void onWrite(BLECharacteristic *pCharacteristic) {
      //保存接收到的数据
      String rxValue = pCharacteristic->getValue();
      //如果接收的数据大于 0
      if (rxValue.length() > 0) {
        context->getTxCharacteristic()->setValue((uint8_t*)rxValue.c_str(), rxValue.length());
        context->getTxCharacteristic()->notify();
      }
    }
};

// LED 闪烁任务
void ledTask(void *pvParameters) {
  BluetoothContext* context = static_cast<BluetoothContext*>(pvParameters);
  while (true) {
    // 动态读取当前 interval（防止任务卡住旧值）
    unsigned long currentInterval = context->getInterval();
    digitalWrite(48, LOW);
    vTaskDelay(currentInterval / 2 / portTICK_PERIOD_MS);
    digitalWrite(48, HIGH);
    vTaskDelay(currentInterval / 2 / portTICK_PERIOD_MS);
  }
}


std::unique_ptr<MyServerCallbacks> serverCallback;
std::unique_ptr<MyCallbacks> charCallback;
TaskHandle_t ledTaskHandle = NULL;

void BluetoothContext::init(const String& deviceName) {
  pinMode(48, OUTPUT);
  // 读取蓝牙 MAC 地址
  //const uint8_t* btMac = esp_bt_dev_get_address();
  //char localDeviceName[20];
  //snprintf(localDeviceName, sizeof(localDeviceName), "YINLUAN_%02X%02X", btMac[0], btMac[1]);
  uint8_t mac_address[6];
  esp_read_mac(mac_address, ESP_MAC_BT);
  char mac_suffix[5]; // 2字节 * 2字符 + 1结尾 = 5
  snprintf(mac_suffix, sizeof(mac_suffix), "%02X%02X", mac_address[0], mac_address[1]);
  // 把外部传入的 deviceName 转为 C 字符串，然后拼接 MAC 后缀
  char localDeviceName[32];
  snprintf(localDeviceName, sizeof(localDeviceName), "%s_%s", deviceName.c_str(), mac_suffix);
  BLEDevice::init(localDeviceName);
  BLEDevice::setMTU(240);
  // 创建蓝牙服务器
  pServer = BLEDevice::createServer();
  serverCallback = std::make_unique<MyServerCallbacks>(this);
  // 设置监听
  pServer->setCallbacks(serverCallback.get());
  // Create the BLE Service
  //设置蓝牙服务UUID
  BLEService *pService = pServer->createService(SERVICE_UUID);
  //设置发送特征码
  pTxCharacteristic = pService->createCharacteristic(
                    CHARACTERISTIC_UUID_TX,
                    BLECharacteristic::PROPERTY_NOTIFY
                  );
  // 设置描述符
  pTxCharacteristic->addDescriptor(new BLE2902());

  //设置接收特征码
  pRxCharacteristic = pService->createCharacteristic(
                      CHARACTERISTIC_UUID_RX,
                      BLECharacteristic::PROPERTY_WRITE | BLECharacteristic::PROPERTY_WRITE_NR
                    );
  pRxCharacteristic->addDescriptor(new BLE2902());


  //设置控制特征码
  pCxCharacteristic = pService->createCharacteristic(
                    CHARACTERISTIC_UUID_CX,
                    BLECharacteristic::PROPERTY_NOTIFY
                  );
  // 设置描述符
  pCxCharacteristic->addDescriptor(new BLE2902());


  charCallback = std::make_unique<MyCallbacks>(this);
  //设置信息监听
  pRxCharacteristic->setCallbacks(charCallback.get());
  // 启动服务器
  pService->start();

  BLEAdvertising *pAdvertising =  pServer->getAdvertising();
  // 设置广播周期：160 * 0.625ms = 100ms
  pAdvertising->setMinInterval(160);
  pAdvertising->setMaxInterval(160);
  // 开启广播
  pAdvertising->start();

  
  // 创建 LED 控制任务
  xTaskCreatePinnedToCore(
    ledTask,          // 任务函数
    "LED Task",       // 名称
    1000,             // 栈大小
    this,             // 参数
    1,                // 优先级
    &ledTaskHandle,   // 任务句柄
    1                 // 运行在 Core 1（通常推荐给非通信任务）
  );
}